﻿
using AutoMapper;
using Mes.Application.Common.Resource;
using Mes.Application.Common;
using Mes.Application.DTO.Inputs.Quality;
using Mes.Application.DTO.Results.Quality;
using Mes.Domain.BoundedContext;
using Mes.Infrastructure.Data.BoundedContext.Repositories.Quality;
using Mes.Domain.BoundedContext.Entities.Quality;
using System.Linq.Expressions;
using Mes.Infrastructure.Data.BoundedContext.Extensions;
using Microsoft.EntityFrameworkCore;

namespace Mes.Application.Services.Quality
{
    public class SamplePlanService : ISamplePlanService
    {
        private readonly IMapper _mapper;
        private readonly ISamplePlanRepository _samplePlanRepository;
        private readonly ISampleFreqRepository _sampleFreqRepository;
        private readonly ISamplePlanFreqLinkRepository _samplePlanFreqLinkRepository;

        public SamplePlanService(IMapper mapper, ISamplePlanRepository samplePlanRepository, ISampleFreqRepository sampleFreqRepository, ISamplePlanFreqLinkRepository samplePlanFreqLinkRepository)
        {
            if (mapper == null || samplePlanRepository == null || sampleFreqRepository == null || samplePlanFreqLinkRepository == null)
            {
                throw new ArgumentNullException();
            }
            _mapper = mapper;
            _samplePlanRepository = samplePlanRepository;
            _sampleFreqRepository = sampleFreqRepository;
            _samplePlanFreqLinkRepository = samplePlanFreqLinkRepository;
        }

        /// <summary>
        /// 添加采样计划，需绑定采样计划频率，否则无法保存
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task AddSamplePlanAsync(SamplePlanAddingInput input)
        {
            // 采样计划名称必须唯一
            if (await _samplePlanRepository.ExistsAsync(x => x.Plan_Name == input.Plan_Name))
            {
                throw new CustomException(Messages.SamplePlanAlreadyExist);
            }

            // 采样计划频率必须存在
            var sampleFreq = _sampleFreqRepository.Find(x => x.Freq_Id == input.Freq_Id);
            if (sampleFreq == null)
            {
                throw new CustomException(Messages.SampleFreqNotFound);
            }

            // 生成采样计划
            var samplePlan = new SamplePlan(input.Plan_Name, input?.Plan_Desc, input.Sample_Name, input?.Spare1, input?.Spare2, input?.Spare3, input?.Spare4, DateTime.Now);
            await _samplePlanRepository.AddAsync(samplePlan);
            int status = _samplePlanRepository.Save();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }

            // 生成的采样计划id不能是负数，否则删除之前插入采样计划表的记录
            if (samplePlan.Plan_Id < 0)
            {
                _samplePlanRepository.Delete(x => x.Plan_Id == samplePlan.Plan_Id);
                status = _samplePlanRepository.Save();
                throw new CustomException(Messages.ErrorGeneratingSamplePlan);
            }

            // 链接采样计划和采样计划频率
            var samplePlanFreqLink = new SamplePlanFreqLink(samplePlan.Plan_Id, input.Freq_Id, DateTime.Now);
            await _samplePlanFreqLinkRepository.AddAsync(samplePlanFreqLink);
            status = _samplePlanFreqLinkRepository.Save();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
        }

        /// <summary>
        /// 更新采样计划（含采样计划关联的采样频率，如果传入了新的采样频率，则会同时更新采样计划关联的采样频率）
        /// 更新sample plan前必须确保sample plan之前设置过关联的sample freq，否则，直接报错
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task UpdateSamplePlanAsync(SamplePlanUpdatingInput input)
        {
            // 采样计划必须存在
            var samplePlan = _samplePlanRepository.Find(x => x.Plan_Id == input.Plan_Id);
            if (samplePlan == null)
            {
                throw new CustomException(Messages.SamplePlanNotFound);
            }

            // 采样计划频率必须存在
            var sampleFreq = _sampleFreqRepository.Find(x => x.Freq_Id == input.Freq_Id);
            if (sampleFreq == null)
            {
                throw new CustomException(Messages.SampleFreqNotFound);
            }

            // 采样计划和采样计划频率的关联记录必须存在
            var samplePlanFreqLink = _samplePlanFreqLinkRepository.Find(x => x.Plan_Id == input.Plan_Id);
            if (samplePlanFreqLink == null)
            {
                throw new CustomException(Messages.SamplePlanFreqNotFound);
            }

            // 更新采样计划
            samplePlan.Plan_Name = input.Plan_Name;
            samplePlan.Plan_Desc = input.Plan_Desc;
            samplePlan.Sample_Name = input.Sample_Name;
            samplePlan.Spare1 = input.Spare1;
            samplePlan.Spare2 = input.Spare2;
            samplePlan.Spare3 = input.Spare3;
            samplePlan.Spare4 = input.Spare4;
            samplePlan.Last_Edit_At = DateTime.Now;
            _samplePlanRepository.Update(samplePlan);
            int status = _samplePlanRepository.Save();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }

            // 更新采样计划关联的采样计划频率
            if (input.Freq_Id != samplePlanFreqLink.Freq_Id)
            {
                DeleteSamplePlanFreqLinkAsync(input.Plan_Id);
                AddSamplePlanFreqLinkAsync(new SamplePlanFreqAddingInput(input.Plan_Id, input.Freq_Id));
            }   
        }

        /// <summary>
        /// 删除采样计划，会同时删除采样计划和采样计划与采样计划频率关联的记录
        /// </summary>
        /// <param name="samplePlanIds"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task DeleteSamplePlanAsync(int[] samplePlanIds)
        {
            Expression<Func<SamplePlan, bool>> samplePlanFilter = x => samplePlanIds.Contains(x.Plan_Id);
            if (samplePlanFilter == null)
            {
                throw new CustomException(Messages.SamplePlanNotFound);
            }

            Expression<Func<SamplePlanFreqLink, bool>> samplePlanFreqLinkFilter = x => samplePlanIds.Contains(x.Plan_Id);
            if (samplePlanFreqLinkFilter == null)
            {
                throw new CustomException(Messages.SamplePlanFreqNotFound);
            }

            await _samplePlanRepository.DeleteAsync(samplePlanFilter);
            await _samplePlanFreqLinkRepository.DeleteAsync(samplePlanFreqLinkFilter);
            int status = _samplePlanRepository.Save();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
        }

        /// <summary>
        /// 查询采样计划，会同时查询采样计划关联的采样计划频率
        /// </summary>
        /// <param name="samplePlanId"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task<SamplePlanResult> GetSamplePlanByIdAsync(int samplePlanId)
        {
            // 采样计划必须存在
            var samplePlan = await _samplePlanRepository.Query().Where(x => x.Plan_Id == samplePlanId).FirstOrDefaultAsync();
            if (samplePlan == null)
            {
                throw new CustomException(Messages.SamplePlanNotFound);
            }

            // 采样计划和采样计划频率的关联记录必须存在
            var samplePlanFreqLink = _samplePlanFreqLinkRepository.Find(x => x.Plan_Id == samplePlan.Plan_Id);
            if (samplePlanFreqLink == null)
            {
                throw new CustomException(Messages.SamplePlanFreqNotFound);
            }

            // 采样计划频率必须存在
            var sampleFreq = _sampleFreqRepository.Find(x => x.Freq_Id == samplePlanFreqLink.Freq_Id);
            if (sampleFreq == null)
            {
                throw new CustomException(Messages.SampleFreqNotFound);
            }
            var result = _mapper.Map<SamplePlanResult>(samplePlan);
            result.Freq_Id = sampleFreq.Freq_Id;
            result.Freq_Name = sampleFreq.Freq_Name;
            return result;
        }

        /// <summary>
        /// 分页查询采样计划，按照plan_id排序
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedItemsData<SamplePlanResult>> GetSamplePlansAsync(GettingSamplePlanPagedInput input)
        {
            Expression<Func<SamplePlan, bool>> filter = x => true;
            if (!string.IsNullOrEmpty(input.KeyWord))
            {
                filter = filter.And(x => x.Plan_Name.Contains(input.KeyWord) || x.Sample_Name.Contains(input.KeyWord));
            }
            var samplePlanResult = _mapper.Map<PagedItemsData<SamplePlanResult>>(await _samplePlanRepository.Query().Where(filter).OrderBy(x => x.Plan_Id).ToPagedAsync(input.PagedInput));
            if (samplePlanResult == null || samplePlanResult.Items.Count() == 0) // 不存在采样计划
            {
                return samplePlanResult;
            }

            // 存在采样计划
            foreach (var item in samplePlanResult.Items)
            {
                // 采样计划和采样计划频率的关联记录必须存在
                var samplePlanFreqLink = _samplePlanFreqLinkRepository.Find(x => x.Plan_Id == item.Plan_Id);
                if (samplePlanFreqLink == null)
                {
                    throw new CustomException(Messages.SamplePlanFreqNotFound);
                }

                // 采样计划关联的采样计划频率必须存在，并获取采样计划频率名称
                var sampleFreq = _sampleFreqRepository.Find(x => x.Freq_Id == samplePlanFreqLink.Freq_Id);
                if (sampleFreq == null)
                {
                    throw new CustomException(Messages.SampleFreqNotFound);
                }
                item.Freq_Id = sampleFreq.Freq_Id;
                item.Freq_Name = sampleFreq.Freq_Name;
            }
            return samplePlanResult;
        }

        /// <summary>
        /// 关联采样计划和采样计划频率
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        private async Task AddSamplePlanFreqLinkAsync(SamplePlanFreqAddingInput input)
        {
            var sampleFreq = _sampleFreqRepository.Find(x => x.Freq_Id == input.Freq_Id);
            if (sampleFreq == null)
            {
                throw new CustomException(Messages.SampleFreqNotFound);
            }

            var samplePlan = _samplePlanRepository.Find(x => x.Plan_Id == input.Plan_Id);
            if (samplePlan == null)
            {
                throw new CustomException(Messages.SamplePlanNotFound);
            }

            var samplePlanFreqLink = new SamplePlanFreqLink(input.Plan_Id, input.Freq_Id, DateTime.Now);
            await _samplePlanFreqLinkRepository.AddAsync(samplePlanFreqLink);
            int status = _samplePlanFreqLinkRepository.Save();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
        }

        /// <summary>
        /// 解除采样计划关联的采样计划频率
        /// </summary>
        /// <param name="samplePlanId"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        private async Task DeleteSamplePlanFreqLinkAsync(int samplePlanId)
        {
            var samplePlan = _samplePlanFreqLinkRepository.Find(x => x.Plan_Id == samplePlanId);
            if (samplePlan == null)
            {
                throw new CustomException(Messages.SamplePlanNotFound);
            }

            _samplePlanFreqLinkRepository.Delete(samplePlan);
            int status = _samplePlanFreqLinkRepository.Save();
            if (status <= 0)
            {
                throw new CustomException(Messages.SavingFailure);
            }
        }
    }
}
